﻿using System;
using System.Collections.Generic;
using System.Globalization;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Markup;
using System.Windows.Media;
using Microsoft.Windows.Controls;

namespace RG.Common.WPF
{
    public abstract class BaseDictionaryConverter: IValueConverter
    {
        protected abstract Dictionary<int, string> Dictionary { get;}

        public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
        {
            if (value == null) return "";
            return Dictionary.SafeGetValue((int) value, "?");
        }

        public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
        {
            return Dictionary.SafeGetKey((string) value, 0);
        }
    }
    
    
    [ValueConversion(typeof(bool), typeof(bool))]
    public class BoolNotConverter : IValueConverter
    {
        public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
        {
            return !(bool)value;
        }

        public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
        {
            return !(bool)value;
        }
    }

    [ValueConversion(typeof(int?), typeof(string))]
    public class GenderConverter : IValueConverter
    {
        #region IValueConverter Members

        public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
        {
            return ClientGender.StringGender((int?)value);
        }

        public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
        {
            foreach (var pair in ClientGender.ClientGenders)
                if (pair.Value == (string)value)
                    return pair.Key;
            return 0;
        }

        #endregion
    }

    [ValueConversion(typeof(bool), typeof(Brush))]
    public class UsedFilterConverter : IValueConverter
    {
        public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
        {
            return (bool) value
                       ? (object) new LinearGradientBrush(
                                      new GradientStopCollection
                                          {
                                              new GradientStop(Color.FromArgb(255, 180, 220, 180), 0),
                                              new GradientStop(Color.FromArgb(255, 180, 220, 180), 0.5),
                                              new GradientStop(Colors.Transparent, 1)
                                          },
                                      45.0)
                       : Colors.Transparent;
        }

        public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
        {
            return null;
        }
    }

    [ValueConversion(typeof(decimal), typeof(string))]
    public class CurrencyConverter : IValueConverter
    {
        public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
        {
            return ((decimal)value).ToString("c", CultureInfo.CreateSpecificCulture("ru-RU"));
        }

        public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
        {
            decimal result;
            decimal.TryParse(value.ToString(), NumberStyles.Number, CultureInfo.CreateSpecificCulture("ru-RU"), out result);
            return result;
        }
    }


    public class IsValueNotNull : IValueConverter
    {
        public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
        {
            return value != null ? Visibility.Visible : Visibility.Collapsed;
        }

        public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
        {
            return value;
        }
    }

    public class IsValueNull : IValueConverter
    {
        public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
        {
            return value != null ? Visibility.Collapsed : Visibility.Visible;
        }

        public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
        {
            return value;
        }
    }

    /// <summary>
    /// Конвертер для стиля шрифта, зачеркнуто/не зачеркнуто (не равно 0/равно 0) удобно использовать для State
    /// </summary>
    [ValueConversion(typeof(int), typeof(TextDecorations))]
    public class StateDecorationsConverter : IValueConverter
    {
        #region IValueConverter Members

        public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
        {
            return (int)value != 0 ? TextDecorations.Strikethrough : null;
        }

        public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
        {
            return 0;
        }

        #endregion
    }

    /// <summary>
    /// Конвертер для стиля шрифта, зачеркнуто/не зачеркнуто (-1/0/1)
    /// </summary>
    [ValueConversion(typeof(int), typeof(TextDecorations))]
    public class DeletedDecorationsConverter : IValueConverter
    {
        #region IValueConverter Members

        public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
        {
            return (int)value == -1 ? TextDecorations.Strikethrough : null;
        }

        public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
        {
            return 0;
        }

        #endregion
    }

    /// <summary>
    /// Конвертер для стиля шрифта, зачеркнуто/не зачеркнуто (-1/0/1)
    /// </summary>
    [ValueConversion(typeof(int), typeof(FontStyle))]
    public class DeletedFontStyleConverter : IValueConverter
    {
        #region IValueConverter Members

        public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
        {
            return (int)value == -1 ? FontStyles.Oblique : FontStyles.Normal;
        }

        public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
        {
            return 0;
        }

        #endregion
    }

    /// <summary>
    /// Конвертер из инта в цвет,        
    /// 0=black
    /// 1=gray
    /// 2=green
    /// 3=navy
    /// </summary>
    [ValueConversion(typeof(int), typeof(Brush))]
    public class HighlightToColorConverter : IValueConverter
    {
        #region IValueConverter Members

        public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
        {
            switch((int)value)
            {
                case 1:
                    return Brushes.Gray;
                case 2:
                    return Brushes.Green;
                case 3:
                    return Brushes.Navy;
                default:
                    return Brushes.Black;
            }
        }

        public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
        {
            return 0;
        }

        #endregion
    }
    
    /// <summary>
    /// Конвертер булевого значения в видимость
    /// </summary>
    [ValueConversion(typeof(bool), typeof(Visibility))]
    public class VisibilityConverter : IValueConverter
    {
        #region IValueConverter Members

        public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
        {
            return (bool)value ? Visibility.Visible : Visibility.Collapsed;
        }

        public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
        {
            return 0;
        }

        #endregion
    }

    /// <summary>
    /// Быстро удваивает подчёркивания,
    /// если лень ставить свойство RecognizesAccessKey в ContentPresenter у кнопок,
    /// текст которых биндится на внешние строки
    /// </summary>
    [ValueConversion(typeof(string), typeof(string))]
    public class TextWithUnderscoreConverter : IValueConverter
    {
        #region IValueConverter Members

        public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
        {
            return ((string) value).Replace("_", "__");
        }

        public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
        {
            return string.Empty;
        }

        #endregion
    }

    /// <summary>
    /// Конвертер булевого значения в видимость
    /// </summary>
    [ValueConversion(typeof(int), typeof(string))]
    public class MonthNameConverter : IValueConverter
    {
        #region IValueConverter Members

        public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
        {
            var date = new DateTime(2000, (int) value, 1);
            return date.ToString("MMMM");
        }

        public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
        {
            return 0;
        }

        #endregion
    }

    /// <summary>
    /// Конвертер булевого значения в видимость со встроенным BoolNotConverter
    /// </summary>
    [ValueConversion(typeof(bool), typeof(Visibility))]
    public class InvertedVisibilityConverter : IValueConverter
    {
        #region IValueConverter Members

        public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
        {
            return (bool)value ? Visibility.Collapsed : Visibility.Visible;
        }

        public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
        {
            return 0;
        }

        #endregion
    }

    /// <summary>
    /// Конвертер булевого значения в видимость
    /// </summary>
    [ValueConversion(typeof(bool), typeof(Visibility))]
    public class VisibilityHiddenConverter : IValueConverter
    {
        #region IValueConverter Members

        public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
        {
            return (bool)value ? Visibility.Visible : Visibility.Hidden;
        }

        public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
        {
            return 0;
        }

        #endregion
    }

    /// <summary>
    /// Конвертер булевого значения в полупрозрачность
    /// </summary>
    [ValueConversion(typeof(bool), typeof(double))]
    public class BoolToHalfOpacityConverter : IValueConverter
    {
        #region IValueConverter Members

        public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
        {
            return (bool)value ? 0.3 : 1;
        }

        public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
        {
            return 0;
        }

        #endregion
    }

    /// <summary>
    /// Конвертер булевого значения в видимость
    /// </summary>
    [ValueConversion(typeof(bool), typeof(DataGridRowDetailsVisibilityMode))]
    public class DataGridRowDetailsVisibilityConverter: IValueConverter
    {
        #region IValueConverter Members

        public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
        {
            if (value == null) return DataGridRowDetailsVisibilityMode.Collapsed;
            return (bool)value ? DataGridRowDetailsVisibilityMode.VisibleWhenSelected : DataGridRowDetailsVisibilityMode.Collapsed;
        }

        public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
        {
            return 0;
        }

        #endregion
    }

    /// <summary>
    /// Конвертер булевого значения в невидимость
    /// </summary>
    [ValueConversion(typeof(bool), typeof(Visibility))]
    public class InvisibilityConverter : IValueConverter
    {
        public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
        {
            return (bool)value ? Visibility.Collapsed : Visibility.Visible;
        }
        public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
        {
            return 0;
        }
    }

    /// <summary>
    /// Конвертер булевого значения в невидимость (скрываем)
    /// </summary>
    [ValueConversion(typeof(bool), typeof(Visibility))]
    public class InvisibilityHiddenConverter : IValueConverter
    {
        public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
        {
            return (bool)value ? Visibility.Hidden : Visibility.Visible;
        }
        public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
        {
            return 0;
        }
    }

    /// <summary>
    /// Конвертер наличия строки в видимость (скрываем пустую строку)
    /// </summary>
    [ValueConversion(typeof(string), typeof(Visibility))]
    public class HiddenByStringIsNullOrEmptyConverter : IValueConverter
    {
        public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
        {
            return string.IsNullOrEmpty((string)value) ? Visibility.Collapsed : Visibility.Visible;
        }
        public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
        {
            return "";
        }
    }

    /// <summary>
    /// Конвертер наличия значения в видимость (скрываем null)
    /// </summary>
    [ValueConversion(typeof(object), typeof(Visibility))]
    public class NullableVisibleConverter : IValueConverter
    {
        public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
        {
            return (value != null) ? Visibility.Visible : Visibility.Collapsed;
        }

        public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
        {
            throw new NotImplementedException();
        }
    }

    /// <summary>
    /// Для скрытия столбца/строки Grid, устанавливая его Width/Height в 0, если переменная биндинга = false
    /// </summary>
    [ValueConversion(typeof(bool), typeof(GridLength))]
    public class BoolToGridLengthConverter : IValueConverter
    {
        public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
        {
            if ((bool)value == false) return new GridLength(0);
            if (parameter != null && (parameter is string) && (string)parameter == "Auto")
                return GridLength.Auto;
            return new GridLength(1, GridUnitType.Star);
        }

        public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
        {
            throw new NotImplementedException();
        }
    }

    /// <summary>
    /// Для скрытия столбца/строки Grid, устанавливая его Width/Height в 0, если переменная биндинга = TRUE
    /// </summary>
    public class InvertedBoolToGridLengthConverter : IValueConverter
    {
        public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
        {
            if ((bool)value == true) return new GridLength(0);
            if (parameter != null && (parameter is string) && (string)parameter == "Auto")
                return GridLength.Auto;
            return new GridLength(1, GridUnitType.Star);
        }

        public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
        {
            throw new NotImplementedException();
        }
    }

    /// <summary>
    /// Выбор Фона из двух значений, переданных как пераметр
    /// </summary>
    [ValueConversion(typeof(bool), typeof(Brush))]
    public class BrushSelectorConverter : IValueConverter
    {
        public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
        {
            var p = ((ArrayExtension)parameter).Items;
            var v = (bool) value;
            return p[v ? 1 : 0];
        }
        public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
        {
            throw new NotImplementedException();
        }
    }

    /// <summary>
    /// Конвертер для стиля шрифта, true - жирное
    /// </summary>
    [ValueConversion(typeof(bool), typeof(FontWeight))]
    public class BoolToBoldConverter : IValueConverter
    {
        #region IValueConverter Members

        public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
        {
            return (bool)value ? FontWeights.Bold : FontWeights.Normal;
        }

        public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
        {
            return 0;
        }

        #endregion
    }

    /// <summary>
    /// Конвертер для положения текста, true - в центр
    /// </summary>
    [ValueConversion(typeof(bool), typeof(TextAlignment))]
    public class BoolToCenterAlignConverter : IValueConverter
    {
        #region IValueConverter Members

        public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
        {
            return (bool)value ? TextAlignment.Center : TextAlignment.Left;
        }

        public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
        {
            return 0;
        }

        #endregion
    }

    /// <summary>
    /// Конвертер для цвета Border'а при наличии ошибки
    /// </summary>
    public class HasErrorToColorConverter : IValueConverter
    {
        public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
        {
            if (typeof(bool).IsAssignableFrom(value.GetType()))
                return ((bool)value)
                           ? (object)new LinearGradientBrush(
                                          new GradientStopCollection
                                              {
                                                  new GradientStop(Colors.Red, 0),
                                                  new GradientStop(Colors.Red, 0.7),
                                                  new GradientStop(Colors.DarkRed, 1),
                                              },
                                          new Point(0, 1),
                                          new Point(1, 0))
                           : Brushes.Transparent;

            return Brushes.Transparent;
        }

        public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
        {
            return false;
        }
    }

    /// <summary>
    /// Конвертер в видимость, если есть ошибка
    /// </summary>
    public class HasErrorToVisibilityConverter : IValueConverter
    {
        public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
        {
            if (typeof(bool).IsAssignableFrom(value.GetType()))
                return ((bool)value) ? Visibility.Visible : Visibility.Collapsed;

            return Visibility.Collapsed;
        }

        public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
        {
            return false;
        }
    }

    /// <summary>
    /// Серый текст в XPS-отчёте, если bool value = false
    /// </summary>
    public class InactiveBrushConverter : IValueConverter
    {
        public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
        {
            if (!(value is bool)) return Brushes.Black;
            return (bool) value ? Brushes.Black : Brushes.Gray;
        }

        public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
        {
            return false;
        }
    }

    [ValueConversion(typeof(string), typeof(VisualBrush))]
    public class ForegroundTextBrushConverter : IValueConverter
    {
        public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
        {
            var text = (string) value;
            return new VisualBrush
                       {
                           Visual = new TextBlock
                                        {
                                            Text = text,
                                            Foreground = new SolidColorBrush
                                                             {
                                                                 Color = Color.FromRgb(0xC0, 0xC0, 0xC0)
                                                             }
                                        }
                       };
        }

        public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
        {
            throw new NotImplementedException();
        }
    }

    /// <summary>
    /// Пол
    /// </summary>
    public static class ClientGender
    {
        public const int Male = 0;
        public const int Female = 1;

        public static readonly Dictionary<int, string> ClientGenders = new Dictionary<int, string>
                                                                           {
                                                                               {Male, "Муж."},
                                                                               {Female, "Жен."},
                                                                           };

        public static string StringGender(int? val)
        {
            if (!val.HasValue) return "";
            string ret;
            ClientGenders.TryGetValue(val.Value, out ret);
            return ret != "" ? ret : "Тип не найден";
        }
    }
}
